/**
 * 新闻整合系统 Looker
 * @author solosky
 */

package net.looker.monitor.crawler;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

import net.looker.work.CallBack;
import net.looker.work.Work;

/**
 * 抓取器抽象类
 * @author solosky
 *
 */


public abstract class Crawler implements Work
{
	/**
	 * 抓取的URL
	 */
	protected URL url;
	
	/**
	 * 网页连接对象
	 */
	protected HttpURLConnection conn;
	
	/**
	 * 标志是否完成
	 * 设置为volatile
	 */
	protected volatile boolean finished;
	
	/**
	 * 标志是否存在错误
	 * 设置为 volatile
	 */
	protected volatile boolean error;
	
	/**
	 * 完成后的回调函数
	 */
	protected CallBack callback;
	
	
	
	/**
	 * 构造函数
	 * @throws MalformedURLException 
	 * @throws MalformedURLException 
	 */
	public Crawler(String url) throws MalformedURLException 
	{
		this.finished = false;
		this.error    = false;
		this.url      = new URL(url);
		this.callback = null;
	}
	
	/**
	 * 构造函数
	 * @param url
	 * @param callback
	 * @throws MalformedURLException
	 */
	public Crawler(String url,CallBack callback) throws MalformedURLException 
	{
		this.finished = false;
		this.error    = false;
		this.url      = new URL(url);
		this.callback = callback;
	}
	/**
	 * 抓取网页
	 * @throws IOException 
	 * @throws CrawlerException 
	 */
	public abstract void crawl() throws IOException, CrawlerException;
	
	/**
	 * 返回抓取内容
	 */
	public abstract Object getCrawled();
	
	/**
	 * 建立连接
	 * @throws IOException 
	 * @throws CrawlerException 
	 */
	protected void openURL() throws IOException, CrawlerException
	{
		//建立连接
		conn = (HttpURLConnection) url.openConnection();
		//检查返回的状态码
		int code = conn.getResponseCode();
		
		switch(code)
		{
		case 302://跳转，建立新的url
			String newUrl = getHeader("Location");
			if (newUrl==null){
				markError();
				throw new CrawlerException("转向文件不存在");
			}
			else{
				//建立新的连接
				url = new URL(newUrl);
				openURL();
			}
			break;
		case 404://文件不存在
			markError();
			throw new CrawlerException("请求文件不存在");
		default:
			break;
		}
	}
	
	/**
	 * 线程调用
	 * 重载线程的开始函数
	 * 如果这个抓取器是多个线程同时抓取，这个函数开始抓取
	 */
	public void startWork()
	{
		try {
			crawl();
		} catch (IOException e) {
			Logger.getLogger("looker").warning("抓取器：IO错误->"+e.getMessage());
		} catch (CrawlerException e) {
			Logger.getLogger("looker").warning("抓取器：抓取异常->"+e.getMessage());
		}finally{
			markFinished();
			if(callback!=null)
				callback.call();
		}
	}
	
	/**
	 * 返回文件头标志
	 */
	public String getHeader(String field)
	{
		return conn.getHeaderField(field);
	}
	
	
	/**
	 * 是否完成任务
	 * @return boolean 任务完成就返回真
	 */
	public boolean isFinished()
	{
		return finished;
	}
	
	/**
	 * 标志完成任务
	 */
	public void markFinished()
	{
		finished = true;
	}
	
	/**
	 * 返回URL
	 */
	public String getUrl()
	{
		return url.toString();
	}
	
	/**
	 * 是否有错误发生
	 * @return boolean
	 */
	public boolean hasError()
	{
		return error;
	}
	
	/**
	 * 标志错误
	 */
	protected void markError()
	{
		error = true;
	}
	
	/**
	 * 设置完成回调函数
	 * @param cb
	 */
	public void setCallBack(CallBack cb)
	{
		callback = cb;
	}
}
